/* Hello, Emacs, this is -*-C-*-
 * $Id: win.trm,v 1.53 2006/12/27 21:40:29 sfeam Exp $
 */

/* GNUPLOT - win.trm */

/*[
 * Copyright 1992 - 1993, 1998, 2004
 *
 * Permission to use, copy, and distribute this software and its
 * documentation for any purpose with or without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear
 * in supporting documentation.
 *
 * Permission to modify the software is granted, but not the right to
 * distribute the complete modified source code.  Modifications are to
 * be distributed as patches to the released version.  Permission to
 * distribute binaries produced by compiling modified sources is granted,
 * provided you
 *   1. distribute the corresponding source modifications from the
 *    released version in the form of a patch file along with the binaries,
 *   2. add special version identification to distinguish your version
 *    in addition to the base release version number,
 *   3. provide your name and address as the primary contact for the
 *    support of your modified version, and
 *   4. retain our contact information in regard to use of the base
 *    software.
 * Permission to distribute the released version of the source code along
 * with corresponding source modifications in the form of a patch file is
 * granted with same provisions 2 through 4 for binary distributions.
 *
 * This software is provided "as is" without express or implied warranty
 * to the extent permitted by applicable law.
]*/

/*
 *
 * AUTHORS
 *
 *   Gnuplot for Windows:
 *       Maurice Castro, Russell Lang
 *
 */


/* This file implements the terminal and printer display for gnuplot  */
/* under Microsoft Windows. The code currently compiles only with the */
/* Borland C++ 3.1 compiler.                                          */
/*                                                                    */
/* The modifications to allow Gnuplot to run under Windows were made  */
/* by Maurice Castro (maurice@bruce.cs.monash.edu.au)                 */
/* and Russell Lang (rjl@monu1.cc.monash.edu.au)         19 Nov 1992  */
/*                                                                    */

/* Edit this file with tabstop=4 (vi :se ts=4)                        */

/*
 * adapted to the new terminal layout by Stefan Bodewig (Dec. 1995)
 */

///#include "driver.h"

#include "../WgnuplotCtl.h"

#ifdef TERM_REGISTER
register_term(windows)
#endif

#ifdef TERM_PROTO
TERM_PUBLIC void WIN_options (void);
TERM_PUBLIC void WIN_init (void);
TERM_PUBLIC void WIN_reset (void);
TERM_PUBLIC void WIN_text (void);
TERM_PUBLIC void WIN_graphics (void);
TERM_PUBLIC void WIN_move (unsigned int x, unsigned int y);
TERM_PUBLIC void WIN_vector (unsigned int x, unsigned int y);
TERM_PUBLIC void WIN_linetype (int lt);
TERM_PUBLIC void WIN_put_text (unsigned int x, unsigned int y, const char *str);
TERM_PUBLIC int WIN_justify_text (enum JUSTIFY mode);
TERM_PUBLIC int WIN_text_angle (int ang);
TERM_PUBLIC void WIN_point (unsigned int x, unsigned int y, int number);
TERM_PUBLIC void WIN_resume (void);
TERM_PUBLIC void WIN_set_pointsize (double);
TERM_PUBLIC void WIN_linewidth (double linewidth);
#ifdef USE_MOUSE
TERM_PUBLIC void WIN_set_ruler (int, int);
TERM_PUBLIC void WIN_set_cursor (int, int, int);
TERM_PUBLIC void WIN_put_tmptext (int, const char str[]);
TERM_PUBLIC void WIN_set_clipboard (const char[]);
#endif
TERM_PUBLIC int WIN_make_palette (t_sm_palette *palette);
TERM_PUBLIC void WIN_set_color (t_colorspec *);
TERM_PUBLIC void WIN_filled_polygon (int points, gpiPoint *corners);
TERM_PUBLIC void WIN_boxfill (int, unsigned int, unsigned int, unsigned int, unsigned int);
/* To support "set term win enhanced" */
TERM_PUBLIC int WIN_set_font (const char *font);
TERM_PUBLIC void WIN_enhanced_put_text (unsigned int x, unsigned int y, const char *str);
TERM_PUBLIC void WIN_enhanced_open (char * fontname, double fontsize,
	    		double base, TBOOLEAN widthflag, TBOOLEAN showflag,
			int overprint);
TERM_PUBLIC void WIN_enhanced_flush (void);
#ifdef WITH_IMAGE
TERM_PUBLIC void WIN_image (unsigned int, unsigned int, coordval *, gpiPoint *, t_imagecolor);
#endif


/* Initialization values - Guess Now Scale later */
#define WIN_XMAX (24000)
#define WIN_YMAX (18000)
#define WIN_HCHAR (WIN_XMAX/75)
#define WIN_VCHAR (WIN_YMAX/25)
#define WIN_HTIC (WIN_XMAX/160)
#define WIN_VTIC WIN_HTIC
#endif /* TERM_PROTO */

#ifndef TERM_PROTO_ONLY
#ifdef TERM_BODY

#include <windows.h>
#include "win/winmain.h"

#ifdef __MSC__
#include <io.h>			/* for mktemp() */
#endif

#define WIN_POINT_TYPES 15	/* 20010411: raised */

/* Interface routines - create list of actions for Windows */

enum WIN_id { WIN_DEFAULT, WIN_MONOCHROME, WIN_COLOR,
	      WIN_ENHANCED, WIN_NOENHANCED, WIN_FONT, WIN_OTHER };

static struct gen_table WIN_opts[] =
{
    { "d$efault", WIN_DEFAULT },
    { "m$onochrome", WIN_MONOCHROME },
    { "c$olor", WIN_COLOR },
    { "c$olour", WIN_COLOR },
    { "noenh$anced", WIN_NOENHANCED },
    { "enh$anced", WIN_ENHANCED },
    { "font", WIN_FONT },
    { NULL, WIN_OTHER }
};

static int WIN_last_linetype = LT_NODRAW; /* HBB 20000813: linetype caching */

/* these variables are needed for enhanced text only */

/* FIXME: these are duplicates of struct graphwin members */
static char WIN_font[MAXFONTNAME] = WINFONT; 
static int WIN_fontsize = WINFONTSIZE;
static double WIN_angle = 0.;  /* unit is radian */

/* FIXME: these should most likely be members of struct graphwin */
static unsigned int WIN_x = 0;
static unsigned int WIN_y = 0;
static enum JUSTIFY WIN_justification = LEFT;

/* state variables for enhanced text processing */
static TBOOLEAN ENHwin_opened_string;
static TBOOLEAN ENHwin_show = TRUE;
static int ENHwin_overprint = 0;
static TBOOLEAN ENHwin_widthflag = TRUE;
static TBOOLEAN ENHwin_sizeonly = FALSE;
static double ENHwin_base;


TERM_PUBLIC void
WIN_options()
{
    char *s;
    TBOOLEAN set_font = FALSE, set_fontsize = FALSE;

    while (!END_OF_COMMAND) {
	switch(lookup_table(&WIN_opts[0],c_token)) {
	case WIN_DEFAULT:
	    graphwin.color = TRUE;
	    strcpy(graphwin.fontname, WINFONT);
	    graphwin.fontsize = WINFONTSIZE;
	    strcpy(graphwin.deffontname, WINFONT);
	    graphwin.deffontsize = WINFONTSIZE;
	    c_token++;
	    break;
	case WIN_MONOCHROME:
	    graphwin.color = FALSE;
	    c_token++;
	    break;
	case WIN_COLOR:
	    graphwin.color = TRUE;
	    c_token++;
	    break;
	case WIN_ENHANCED:
	    c_token++;
	    term->put_text = WIN_enhanced_put_text;
	    term->flags |= TERM_ENHANCED_TEXT;
	    break;
	case WIN_NOENHANCED:
	    c_token++;
	    term->put_text = WIN_put_text;
	    term->flags &= ~TERM_ENHANCED_TEXT;
	    break;
	case WIN_FONT:
	    c_token++;
	    /* Fall through to attempt to read font name */
	case WIN_OTHER:
	default:
	    /* Code copied from ps.trm and modified for windows terminal */
	    if ((s = try_to_get_string())) {
		char *comma;
		if (set_font)
		    int_error(c_token,
			      "extraneous argument in set terminal %s",
			      term->name);
		set_font = TRUE;
	        comma = strrchr(s,',');
	        if (comma && (1 == sscanf(comma+1,"%i", &graphwin.fontsize))) {
		    graphwin.deffontsize = graphwin.fontsize;
		    set_fontsize = TRUE;
		    *comma = '\0';
		}
		if (*s) {
		    strncpy(graphwin.fontname, s, MAX_ID_LEN);
		    strcpy(graphwin.deffontname, graphwin.fontname);
		    free(s);
    		}
	    } else {
		if (set_fontsize)
		    int_error(c_token,
			      "extraneous argument in set terminal %s",
			      term->name);
		set_fontsize = TRUE;
		/* We have font size specified */
		graphwin.fontsize = int_expression();
		graphwin.deffontsize = graphwin.fontsize;
	    }
	    break;
	}
    }

    if (graphwin.fontname[0] == '\0')
	sprintf(term_options, "%s %s", 
		graphwin.color ? "color" : "monochrome", 
		term->flags & TERM_ENHANCED_TEXT ? "enhanced" : "noenhanced");
    else
	sprintf(term_options, "%s %s font \"%s, %d\"",
		graphwin.color ? "color" : "monochrome",
		term->flags & TERM_ENHANCED_TEXT ? "enhanced" : "noenhanced",
		graphwin.fontname, graphwin.fontsize);

    if (IsWindow(graphwin.hWndGraph) && IsIconic(graphwin.hWndGraph))
	ShowWindow(graphwin.hWndGraph, SW_SHOWNORMAL);

    GraphRedraw(&graphwin);
}

/* We don't actually do scaling, but we need to fix up the text size
 * if the user has resized the window.
 * Routine unused -- terminals are not allowed to do their own scale().
 */
#if 0
int
WIN_scale()
{
    term->h_char = graphwin.hchar;
    term->v_char = graphwin.vchar;
    term->h_tic = graphwin.htic;
    term->v_tic = graphwin.vtic;
    sprintf(term_options, "%s \"%s\" %d",
	    graphwin.color ? "color" : "monochrome",
	    graphwin.fontname, graphwin.fontsize);
    return FALSE;		/* can't be done */
}
#endif

TERM_PUBLIC void WIN_init()
{
	CWgnuplotCtrl* pCtrl = CWgnuplotCtrl::GetInstance();

    if (!graphwin.hWndGraph) 
    {
	graphwin.xmax = WIN_XMAX;
	graphwin.ymax = WIN_YMAX;
	graphwin.htic = WIN_HTIC;
	graphwin.vtic = WIN_VTIC;
	pCtrl->GraphInit(&graphwin);
#ifdef WIN32
	SetClassLong(graphwin.hWndGraph, GCL_HICON, (LONG) LoadIcon(graphwin.hInstance, "GRPICON"));
#else
	SetClassWord(graphwin.hWndGraph, GCW_HICON, LoadIcon(graphwin.hInstance, "GRPICON"));
#endif
	graphwin.resized = FALSE;
    }
    WIN_last_linetype = LT_NODRAW;	/* HBB 20000813: linetype caching */
}


TERM_PUBLIC void
WIN_reset()
{
}

TERM_PUBLIC void
WIN_text()
{
    GraphEnd(&graphwin);
}

TERM_PUBLIC void
WIN_graphics()
{
    GraphStart(&graphwin, pointsize);
    WIN_last_linetype = LT_NODRAW;		/* HBB 20000813: linetype caching */
}

TERM_PUBLIC void
WIN_move(unsigned int x, unsigned int y)
{
    /* Notice HBB 20010208: on Win32 platforms, passing int or
     * unsigned int arguments to GraphOp() might cause problems: int
     * is 32bits, but GraphOp() args are 16bit WORDS. */
    GraphOp(&graphwin, W_move, x, y, NULL);

    /* save current position, only needed for enhanced text */
    WIN_x = x; 
    WIN_y = y;
}

TERM_PUBLIC void
WIN_vector(unsigned int x, unsigned int y)
{
    /* Notice HBB 20010208: --> WIN_move() */
    GraphOp(&graphwin, W_vect, x, y, NULL);
}

TERM_PUBLIC void
WIN_linetype(int lt)
{
    if (lt != WIN_last_linetype) {
	/* Notice HBB 20010208: --> see WIN_move() */
    	GraphOp(&graphwin, W_line_type, lt, 0, NULL);
	WIN_last_linetype = lt;
    }
}

TERM_PUBLIC void
WIN_put_text(unsigned int x, unsigned int y, const char *str)
{
    /* Notice HBB 20010208: --> WIN_move() */
    GraphOp(&graphwin, W_put_text, x, y, str);
}

TERM_PUBLIC int
WIN_justify_text(enum JUSTIFY mode)
{
    /* Notice HBB 20010208: --> WIN_move() */
    GraphOp(&graphwin, W_justify, mode, 0, NULL);
    /* store text justification, only needed for enhanced text */
    WIN_justification = mode;
    return (TRUE);
}

TERM_PUBLIC int
WIN_text_angle(int ang)
{
    if (graphwin.rotate) {
	/* Notice HBB 20010208: --> WIN_move() */
 	GraphOp(&graphwin, W_text_angle, ang, 0, NULL);

        /* store text angle, only needed for enhanced text */
	WIN_angle = (double)ang * M_PI / 180.;
    }
    return graphwin.rotate;
}

TERM_PUBLIC void
WIN_point(unsigned int x, unsigned int y, int number)
{
    /* draw point shapes later to save memory */
    /* size of point symbols */
    graphwin.htic = pointsize * term->h_tic / 2;
    graphwin.vtic = pointsize * term->v_tic / 2;
    /* HBB 20010411: secure against pointtype -1 or lower */
    if (number < -1)
	number = -1;		/* refuse nonsense values */
    if (number >= 0)
	number %= WIN_POINT_TYPES;
    number += 1;
    /* Notice HBB 20010208: --> WIN_move() */
    GraphOp(&graphwin, W_dot + number, x, y, NULL);
}

TERM_PUBLIC void
WIN_resume()
{
    GraphResume(&graphwin);
}

TERM_PUBLIC void
WIN_set_pointsize(double s)
{
    /* Save new pointsize as string */
    char scale[30];

    if (s < 0)
	s = 1;
    sprintf(scale, "%.15g", s);
#if 1
    /* HBB 980309: it seems passing it as a string is a bad idea
     * in Win16: it means the wgnuplot.dll has to parse the string
     * via sscanf(), leading to crash (by stack overflow?). Alternative:
     * pass it as a scaled-up integer. For the sake of compatibility,
     * pass the string as well. */
    /* Notice HBB 20010208: --> WIN_move() */
    GraphOp(&graphwin, W_pointsize, (int) 100 * s, 0, scale);
#else
    GraphOp(&graphwin, W_pointsize, 0, 0, scale);
#endif
}

TERM_PUBLIC void
WIN_linewidth(double linewidth)
{
    /* HBB 20000813: New routine */
    WIN_last_linetype = LT_NODRAW;        /* invalidate cached linetype */
    /* Notice HBB 20010208: --> WIN_move() */
    GraphOp(&graphwin, W_line_width, (int) 100 * linewidth, 0, NULL);
}

#ifdef USE_MOUSE

/* Implemented by Petr Mikulik, February 2001 --- the best Windows solutions
 * come from OS/2 :-))
 */

TERM_PUBLIC void
WIN_put_tmptext ( int i, const char str[] )
{
    Graph_put_tmptext(&graphwin, i, str );
}

TERM_PUBLIC void
WIN_set_ruler ( int x, int y )
{
    Graph_set_ruler(&graphwin, x, y );
}

TERM_PUBLIC void
WIN_set_cursor ( int c, int x, int y )
{
    Graph_set_cursor(&graphwin, c, x, y );
}

TERM_PUBLIC void
WIN_set_clipboard ( const char s[] )
{
    Graph_set_clipboard(&graphwin, s);
}

#endif /* USE_MOUSE */


#ifdef WITH_IMAGE

/* Note: this is a verbatim copy of PM_image (pm.trm) with only minor changes */

TERM_PUBLIC void
WIN_image(unsigned int M, unsigned int N, coordval *image,
	  gpiPoint *corner, t_imagecolor color_mode)
{
    PBYTE rgb_image;
    unsigned int image_size;
    unsigned int pad_bytes;

    /* IC_PALETTE and IC_RGB images are converted to a 24bit RGB format
       suitable for Windows:
        - sequence of lines is reversed 
        - each line starts at a 4 byte boundary
    */

    /* fprintf(stderr, "WIN_image: %i x %i, mode=%s\n", M, N, color_mode==IC_RGB?"IC_RGB":"IC_PALETTE" ); */
    pad_bytes = (4 - (3 * M) % 4) % 4; /* scan lines start on ULONG boundaries */

    image_size = (M + pad_bytes ) * N * 3;
    rgb_image = (PBYTE) gp_alloc(image_size, "WIN RGB image");

    if (color_mode == IC_PALETTE) {
    	unsigned int x, y;

	rgb_image += N * (3 * M + pad_bytes);
	for (y=0; y<N; y++) {
	    rgb_image -= 3 * M + pad_bytes;
	    for(x=0; x<M; x++) {
		rgb255_color rgb255;
		rgb255maxcolors_from_gray(*image++, &rgb255);
		*(rgb_image++) = rgb255.b;
		*(rgb_image++) = rgb255.g;
		*(rgb_image++) = rgb255.r;
	    }
	    rgb_image -= 3 * M;
	}
    } else if (color_mode == IC_RGB) {
    	unsigned int x, y;

	rgb_image += N * (3 * M + pad_bytes);
	for (y=0; y<N; y++) {
	    rgb_image -= 3 * M + pad_bytes;
	    for(x=0; x<M; x++) {
		rgb255_color rgb255;
		rgb255.r = (BYTE) (*image++ * 255 + 0.5);
		rgb255.g = (BYTE) (*image++ * 255 + 0.5);
		rgb255.b = (BYTE) (*image++ * 255 + 0.5);
		*(rgb_image++) = rgb255.b;
		*(rgb_image++) = rgb255.g;
		*(rgb_image++) = rgb255.r;
	    }
	    rgb_image -= 3 * M;
	}
    }

    /* squeze all the information into the buffer */
    if ((color_mode == IC_PALETTE) || (color_mode == IC_RGB)) {
        GraphOp(&graphwin, W_image, corner[0].x, corner[0].y, NULL);
        GraphOp(&graphwin, W_image, corner[1].x, corner[1].y, NULL);
        GraphOp(&graphwin, W_image, corner[2].x, corner[2].y, NULL);
        GraphOp(&graphwin, W_image, corner[3].x, corner[3].y, NULL);
	/* GraphOp() cannot be used here since the image might 
	   contain char(0), so use  GraphOpSize() instead */
        GraphOpSize(&graphwin, W_image, M, N, rgb_image, image_size);
    }

    free(rgb_image);
}

#endif /* WITH_IMAGE */


TERM_PUBLIC int
WIN_make_palette(t_sm_palette *palette)
{
    /* Win can do continuous colors. However, we round them only to 256 levels
     * in order to pass an integer to GraphOp; it also reasonably limits
     * the number of colors if "copy to clipboard" is used. Don't change this
     * number unless you change it also in WIN_set_color() and in wgraph.c.
     */
    return 256;
}

TERM_PUBLIC void
WIN_set_color(t_colorspec *colorspec)
{
    switch (colorspec->type ) {
	case TC_FRAC:
    WIN_last_linetype = LT_NODRAW;      /* invalidate cached linetype */
    GraphOp(&graphwin, W_pm3d_setcolor, (int)(256*colorspec->value), 0, NULL);
	    break;
	case TC_RGB:
	    GraphOp(&graphwin, W_pm3d_setcolor, (colorspec->lt) & 0xffff, 0xff00 | ((colorspec->lt >> 16) & 0x00ff), NULL);
	    break;
	case TC_LT:
	    WIN_linetype(colorspec->lt);
	    break;
    }
}

TERM_PUBLIC void
WIN_filled_polygon(int points, gpiPoint *corners)
{
    int i;
    /* Notice HBB 20010208: --> WIN_move() */
    for (i=0; i<points; i++)
    	GraphOp(&graphwin, W_pm3d_filled_polygon_pt, corners[i].x, corners[i].y, NULL);
    /* finish series: */
    GraphOp(&graphwin, W_pm3d_filled_polygon_draw, points, 0, NULL);
}

TERM_PUBLIC void
WIN_boxfill(
    int style,
    unsigned int xleft, unsigned int ybottom,
    unsigned int width, unsigned int height)
{
    /* split into two commands to squeeze through all the necessary info */
    /* Notice HBB 20010208: --> WIN_move() */
    GraphOp(&graphwin, W_fillstyle, style, 0, NULL);
    GraphOp(&graphwin, W_move, xleft, ybottom, NULL);
    GraphOp(&graphwin, W_boxfill, width, height, NULL);
}


TERM_PUBLIC int
WIN_set_font(const char *font)
{
    char fontname[MAXFONTNAME];
    int  fontsize;

    if (font != NULL) {
	if (font[0] == '\0') {
	    strcpy(fontname, graphwin.deffontname);
	    fontsize = graphwin.deffontsize;
	} else {
	    const char* size = strrchr(font, ',');
	    if (size == NULL) {
		/* only font name given */
		strcpy(fontname, font);
    		fontsize = graphwin.deffontsize;
	    } else if (size == font) {
		/* only font size given */
		strcpy(fontname, graphwin.deffontname);
		sscanf(size+1,"%i", &fontsize);
	    } else {
		/* full font information supplied */
		strncpy(fontname, font, size-font);
		fontname[size-font] = '\0';
		sscanf(size+1,"%i", &fontsize);
	    }
	}
    }

    if (font != NULL) {
	GraphOp(&graphwin, W_font, fontsize, 0, fontname);
        strcpy(WIN_font, fontname);
        WIN_fontsize = fontsize;
    }
    else {
	GraphOp(&graphwin, W_font, 0, 0, "");
        strcpy(WIN_font, graphwin.deffontname);
        WIN_fontsize = graphwin.deffontsize;
    }
    return TRUE;
}


TERM_PUBLIC void
WIN_enhanced_open(
    char *fontname,
    double fontsize, double base,
    TBOOLEAN widthflag, TBOOLEAN showflag,
    int overprint)
{
    static const int win_scale = 40; /* scaling of base offset */  
    static unsigned int ENHwin_xsave, ENHwin_ysave;
    char *fontstring;

    /* There are two special cases:
     * overprint = 3 means save current position
     * overprint = 4 means restore saved position
     */
    if (overprint == 3) {
	ENHwin_xsave = WIN_x;
	ENHwin_ysave = WIN_y;
	return;
    } else if (overprint == 4) {
	WIN_x = ENHwin_xsave;
	WIN_y = ENHwin_ysave;
	return;
    }

    if (!ENHwin_opened_string) {
	ENHwin_opened_string = TRUE;

	/* Start new text fragment */
	enhanced_cur_text = &enhanced_text[0];

	/* Keep track of whether we are supposed to show this string */
	ENHwin_show = showflag;

	/* 0/1/2  no overprint / 1st pass / 2nd pass */
	ENHwin_overprint = overprint;

	/* widthflag FALSE means do not update text position after printing */
	ENHwin_widthflag = widthflag;

	/* Scale fractional font height to vertical units of display */
	/* FIXME:	
		Font scaling is not done properly (yet) and will lead to
		non-optimal results for most font and size selections.
		OUTLINEFONTMETRICS could be used for better here.
	*/
	ENHwin_base = win_scale * base;
	 
 	/* Select font */
	/* FIXME: It would be nice to have fractional font sizes 
	          for super- and subscripts. */
	/* FIXME: sometimes fontname has zero length */
	if ((fontname != NULL) && strlen(fontname) > 0) {
	    fontstring = (char *)malloc(strlen(fontname) + 16);
	    sprintf(fontstring, "%s,%i", fontname, (int)fontsize);
	} else {
	    fontstring = (char *)malloc( strlen(graphwin.deffontname) + 16 );
	    sprintf( fontstring, "%s,%i", graphwin.deffontname, fontsize);
	}
	WIN_set_font( fontstring );
	free( fontstring );
   }
}


TERM_PUBLIC void
WIN_enhanced_flush()
{
    static unsigned int ENHwin_xsave, ENHwin_ysave;

    if (ENHwin_opened_string) {
	int width, height;
	unsigned int x, y, len;

	*enhanced_cur_text = '\0';
	
	/* print the string fragment, perhaps invisibly */
	/* NB: base expresses offset from current y pos */
	x = WIN_x - ENHwin_base * sin(WIN_angle);
	y = WIN_y + ENHwin_base * cos(WIN_angle);

	/* calculate length of string first */
    	len = GraphGetTextLength(&graphwin, enhanced_text, WIN_font, WIN_fontsize);
	width = cos(WIN_angle) * len;
	height = sin(WIN_angle) * len;

	if (ENHwin_show && !ENHwin_sizeonly) {
	    /* display string */
	    GraphOp(&graphwin, W_put_text, x, y, enhanced_text);
	}

	/* update drawing position according to len */
	if (!ENHwin_widthflag) {
	    width = 0; 
	    height = 0;
	}
	if (ENHwin_sizeonly) {
	    /* This is the first pass for justified printing.        */
	    /* We just adjust the starting position for second pass. */
	    if (WIN_justification == RIGHT) {
		WIN_x -= width;
		WIN_y -= height;
	    }
	    else if (WIN_justification == CENTRE) {
		WIN_x -= width / 2;
		WIN_y -= height / 2;
	    }
	    /* nothing to do for LEFT justified text */
	}
	else if (ENHwin_overprint == 1) {
	    /* Save current position */
	    ENHwin_xsave = WIN_x + width;
	    ENHwin_ysave = WIN_y + height;
	    /* First pass of overprint, leave position in center of fragment */
	    WIN_x += width / 2;
	    WIN_y += height / 2;
	}
	else if (ENHwin_overprint == 2) {
	    /* Restore current position,                          */
	    /* this sets the position behind the overprinted text */
	    WIN_x = ENHwin_xsave;
	    WIN_y = ENHwin_ysave;
	}
	else {
	    /* Normal case is to update position to end of fragment */
	    WIN_x += width;
	    WIN_y += height;
	}

	ENHwin_opened_string = FALSE;
    }
}


TERM_PUBLIC void
WIN_enhanced_put_text(unsigned int x, unsigned int y, const char *str)
{
    char *original_string = (char *)str;
    unsigned int pass, num_passes;

    /* If no enhanced text processing is needed, we can use the plain  */
    /* vanilla put_text() routine instead of this fancy recursive one. */
    if (ignore_enhanced_text || !strpbrk(str, "{}^_@&~")) {
	WIN_put_text(x,y,str);
	return;
    }

    /* Set up global variables needed by enhanced_recursion() */
    ENHwin_opened_string = FALSE;
    enhanced_fontscale = 1.0;
    strncpy(enhanced_escape_format,"%c",sizeof(enhanced_escape_format));

    /* Tell the terminal to move the drawing position */
    /* we store the current position to WIN_x and WIN_y */
    WIN_x = x; 
    WIN_y = y;

    /* Text justification requires two passes. During the first pass we */
    /* don't draw anything, we just measure the space it will take.     */
    /* Without justification one pass is enough                         */
    if (WIN_justification == LEFT) {
	num_passes = 1;
    }
    else {
	num_passes = 2;
	ENHwin_sizeonly = TRUE; 
    }

    for( pass=1; pass <= num_passes; pass++ ) {

	/* This will restore the default font 
	   and update WIN_font and WIN_fontsize */
	WIN_set_font(NULL); 

	/* Set the recursion going. We say to keep going until a
	* closing brace, but we don't really expect to find one.
	* If the return value is not the nul-terminator of the
	* string, that can only mean that we did find an unmatched
	* closing brace in the string. We increment past it (else
	* we get stuck in an infinite loop) and try again.
	*/
	while (*(str = enhanced_recursion((char *)str, TRUE,
			NULL, WIN_fontsize,
			0.0, TRUE, TRUE, 0))) {
	    (term->enhanced_flush)();

	    /* I think we can only get here if *str == '}' */
	    enh_err_check(str);

	    if (!*++str)
	    	break; /* end of string */

	    /* else carry on and process the rest of the string */
	}

	/* In order to do text justification we need to do a second pass that */
	/* uses information stored during the first pass.                     */
	/* see WIN_enhanced_flush()                                           */
	if (pass == 1) {
	    /* do the actual printing in the next pass */
	    ENHwin_sizeonly = FALSE;
	    str = original_string;

	    /* temporarily switch to left alignment since we do it ourselves */
	    GraphOp(&graphwin, W_justify, LEFT, 0, NULL);
	}
    }

    /* restore default font */
    WIN_set_font(NULL); 

    /* restore text alignment */
    if (num_passes > 1)
        GraphOp(&graphwin, W_justify, WIN_justification, 0, NULL);
}

#endif /* TERM_BODY */

#ifdef TERM_TABLE

TERM_TABLE_START(win_driver)
    "windows", "Microsoft Windows",
    WIN_XMAX, WIN_YMAX, WIN_VCHAR, WIN_HCHAR,
    WIN_VTIC, WIN_HTIC, WIN_options, WIN_init, WIN_reset,
    WIN_text, null_scale, WIN_graphics, WIN_move, WIN_vector,
    WIN_linetype, WIN_put_text, WIN_text_angle,
    WIN_justify_text, WIN_point, do_arrow, WIN_set_font,
    WIN_set_pointsize, TERM_CAN_MULTIPLOT|TERM_NO_OUTPUTFILE,
    WIN_text /* suspend */ , WIN_resume,
    WIN_boxfill, WIN_linewidth
#ifdef USE_MOUSE
    , 0 /* WIN_waitforinput */,
    WIN_put_tmptext, WIN_set_ruler, WIN_set_cursor, WIN_set_clipboard
#endif
    , WIN_make_palette, 0 /* previous_palette */,
    WIN_set_color, WIN_filled_polygon
#ifdef WITH_IMAGE
    , WIN_image
#endif
    , WIN_enhanced_open, WIN_enhanced_flush, do_enh_writec
TERM_TABLE_END(win_driver)

#undef LAST_TERM
#define LAST_TERM win_driver

#endif /* TERM_TABLE */
#endif /* TERM_PROTO_ONLY */

#ifdef TERM_HELP
START_HELP(windows)
"1 windows",
"?commands set terminal windows",
"?set terminal windows",
"?set term windows",
"?terminal windows",
"?term windows",
"?windows",
" Three options may be set in the `windows` terminal driver.",
"",
" Syntax:",
"       set terminal windows {color | monochrome}",
"                            {enhanced | noenhanced}",
"                            {{font} \"fontname{,fontsize}\" {<fontsize>}}",
"",
" where `color` and `monochrome` select colored or mono output,", 
" `enhanced` enables enhanced text mode features (subscripts,",
" superscripts and mixed fonts). See `enhanced` for more information.",
" `\"<fontname>\"` is the name of a valid Windows font, and `<fontsize>`",
" is the size of the font in points.",
"",
" Other options may be set with the graph-menu, the initialization file,",
" and `set linestyle`.  Note that there is one restriction imposed by",
" the classic Windows GDI interface: modifiable linewidth only works with",
" solid lines, not with dotted or dashed ones.",
/* Does this really belong here? If not, someone move it where it does. */
"",
" The Windows version normally terminates immediately as soon as the end of",
" any files given as command line arguments is reached (i.e. in non-interactive",
" mode), unless you specify `-` as the last command line option.",
" It will also not show the text-window at all, in this mode, only the plot.",
" By giving the optional argument `-persist` (same as for gnuplot under x11;",
" former Windows-only options `/noend` or `-noend` are still accepted as well),",
" will not close gnuplot. Contrary to gnuplot on other operating systems,",
" gnuplot's interactive command line is accessible after the -persist option.",
"2 graph-menu",
"?commands set terminal windows graph-menu",
"?set terminal windows graph-menu",
"?set term windows graph-menu",
"?windows graph-menu",
"?graph-menu",
" The `gnuplot graph` window has the following options on a pop-up menu",
" accessed by pressing the right mouse button or selecting `Options` from the",
" system menu:",
"",
" `Bring to Top` when checked brings the graph window to the top after every",
" plot.",
"",
" `Color` when checked enables color linestyles.  When unchecked it forces",
" monochrome linestyles.",
"",
" `Copy to Clipboard` copies a bitmap and a Metafile picture.",
"",
" `Background...` sets the window background color.",
"",
" `Choose Font...` selects the font used in the graphics window.",
"",
" `Line Styles...` allows customization of the line colors and styles.",
"",
" `Print...` prints the graphics windows using a Windows printer driver and",
" allows selection of the printer and scaling of the output.  The output",
" produced by `Print` is not as good as that from `gnuplot`'s own printer",
" drivers.",
"",
" `Update wgnuplot.ini` saves the current window locations, window sizes, text",
" window font, text window font size, graph window font, graph window font",
" size, background color and linestyles to the initialization file",
" `WGNUPLOT.INI`.",
"2 printing",
"?commands set terminal windows printing",
"?set terminal windows printing",
"?set term windows printing",
"?windows printing",
"?printing",
" In order of preference, graphs may be be printed in the following ways.",
"",
" `1.` Use the `gnuplot` command `set terminal` to select a printer and `set",
" output` to redirect output to a file.",
"",
" `2.` Select the `Print...` command from the `gnuplot graph` window.  An extra",
" command `screendump` does this from the text window.",
"",
" `3.` If `set output \"PRN\"` is used, output will go to a temporary file.  When",
" you exit from `gnuplot` or when you change the output with another `set",
" output` command, a dialog box will appear for you to select a printer port.",
" If you choose OK, the output will be printed on the selected port, passing",
" unmodified through the print manager.  It is possible to accidentally (or",
" deliberately) send printer output meant for one printer to an incompatible",
" printer.",
"2 text-menu",
"?commands set terminal windows text-menu",
"?set terminal windows text-menu",
"?set term windows text-menu",
"?windows text-menu",
"?text-menu",
" The `gnuplot text` window has the following options on a pop-up menu accessed",
" by pressing the right mouse button or selecting `Options` from the system",
" menu:",
"",
" `Copy to Clipboard` copies marked text to the clipboard.",
"",
" `Paste` copies text from the clipboard as if typed by the user.",
"",
" `Choose Font...` selects the font used in the text window.",
"",
" `System Colors` when selected makes the text window honor the System Colors",
" set using the Control Panel.  When unselected, text is black or blue on a",
" white background.",
"",
" `Update wgnuplot.ini` saves the current text window location, text window",
" size, text window font and text window font size to the initialisation file",
" `WGNUPLOT.INI`.",
"",
" `MENU BAR`",
"",
" If the menu file `WGNUPLOT.MNU` is found in the same directory as",
" WGNUPLOT.EXE, then the menu specified in `WGNUPLOT.MNU` will be loaded.",
" Menu commands:",
"",
" [Menu] starts a new menu with the name on the following line.",
"",
" [EndMenu] ends the current menu.",
"",
" [--] inserts a horizontal menu separator.",
"",
" [|] inserts a vertical menu separator.",
"",
" [Button] puts the next macro on a push button instead of a menu.",
"",
" Macros take two lines with the macro name (menu entry) on the first line and",
" the macro on the second line.  Leading spaces are ignored.  Macro commands:",
"",
" [INPUT] --- Input string with prompt terminated by [EOS] or {ENTER}",
"",
" [EOS] --- End Of String terminator.  Generates no output.",
"",
" [OPEN] --- Get name of file to open from list box, with title of list box",
" terminated by [EOS], followed by default filename terminated by [EOS] or",
" {ENTER}.  This uses COMMDLG.DLL from Windows 3.1.",
"",
" [SAVE] --- Get name of file to save.  Similar to [OPEN]",
"",
" Macro character substitutions:",
"",
" {ENTER} --- Carriage Return '\\r'",
"",
" {TAB} --- Tab '\\011'",
"",
" {ESC} --- Escape '\\033'",
"",
" {^A} --- '\\001'",
"",
" ...",
"",
" {^_} --- '\\031'",
"",
" Macros are limited to 256 characters after expansion.",
"2 wgnuplot.ini",
"?commands set terminal windows wgnuplot.ini",
"?set terminal windows wgnuplot.ini",
"?set term windows wgnuplot.ini",
"?windows wgnuplot.ini",
"?wgnuplot.ini",
" Windows `gnuplot` will read some of its options from the `[WGNUPLOT]` section",
" of `WGNUPLOT.INI` in the Windows directory.  A sample `WGNUPLOT.INI` file:",
"",
"       [WGNUPLOT]",
"       TextOrigin=0 0",
"       TextSize=640 150",
"       TextFont=Terminal,9",
"       GraphOrigin=0 150",
"       GraphSize=640 330",
"       GraphFont=Arial,10",
"       GraphColor=1",
"       GraphToTop=1",
"       GraphBackground=255 255 255",
"       Border=0 0 0 0 0",
"       Axis=192 192 192 2 2",
"       Line1=0 0 255 0 0",
"       Line2=0 255 0 0 1",
"       Line3=255 0 0 0 2",
"       Line4=255 0 255 0 3",
"       Line5=0 0 128 0 4",
"",
" The `GraphFont` entry specifies the font name and size in points.  The five",
" numbers given in the `Border`, `Axis` and `Line` entries are the `Red`",
" intensity (0--255), `Green` intensity, `Blue` intensity, `Color Linestyle`",
" and `Mono Linestyle`.  `Linestyles` are 0=SOLID, 1=DASH, 2=DOT, 3=DASHDOT,",
" 4=DASHDOTDOT.  In the sample `WGNUPLOT.INI` file above, Line 2 is a green",
" solid line in color mode, or a dashed line in monochrome mode.  The default",
" line width is 1 pixel.  If `Linestyle` is negative, it specifies the width of",
" a SOLID line in pixels.  Line1 and any linestyle used with the `points` style",
" must be SOLID with unit width.",
"2 windows3.0",
"?commands set terminal windows windows3.0",
"?set terminal windows windows3.0",
"?set term windows windows3.0",
"?windows windows3.0",
"?windows3.0",
" Windows 3.1 is preferred, but WGNUPLOT will run under Windows 3.0 with the",
" following restrictions:",
" `1.` COMMDLG.DLL and SHELL.DLL (available with Windows 3.1 or Borland C++",
" 3.1) must be in the windows directory.",
"",
" `2.` WGNUPLOT.HLP produced by Borland C++ 3.1 is in Windows 3.1 format.",
" You need to use the WINHELP.EXE supplied with Borland C++ 3.1.",
"",
" `3.` It will not run in real mode due to lack of memory.",
"",
" `4.` TrueType fonts are not available in the graph window.",
"",
" `5.` Drag-drop does not work."
END_HELP(windows)
#endif /* TERM_HELP */
